﻿using System;
using System.Collections.Generic;

namespace TradeClient.Logic.TradeCore
{
    /// <summary>
    /// 策略类基类（定义了行情接口和交易接口）
    /// 策略类必须实现该接口，以便行情线程能调用策略进行交易
    /// 策略类必须实现单例模式
    /// </summary>
    public abstract class PolicyBase
    {
        /// <summary>
        /// 操作函数代理
        /// </summary>
        /// <returns></returns>
        private delegate bool DelegateAction();

        /// <summary>
        /// 该策略管理的账户列表
        /// </summary>
        private List<CtpAccount> ctpAccounts;

        /// <summary>
        /// 引发事件K线序列
        /// </summary>
        protected KLineSeries kLineSeries;

        /// <summary>
        /// 交易接口对象
        /// </summary>
        protected TradeManager tradeManager;

        /// <summary>
        /// 操作类别
        /// </summary>
        protected enum ActionType
        {
            /// <summary>
            /// 开仓操作
            /// </summary>
            OpenPosition,

            /// <summary>
            /// 加仓操作
            /// </summary>
            IncreasePosition,

            /// <summary>
            /// 平仓操作
            /// </summary>
            ClosePosition
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="paramTradeManager">交易接口对象</param>
        protected PolicyBase()
        {
            ctpAccounts  = new List<CtpAccount>(10);
            tradeManager = TradeManager.GetInstance();
        }
        
        /// <summary>
        /// 加入要被交易的账户
        /// </summary>
        /// <param name="ctpAccount">CTP账户</param>
        public void AddCtpAccount(CtpAccount ctpAccount)
        {
            this.ctpAccounts.Add(ctpAccount);
        }

        /// <summary>
        /// 开仓操作
        /// </summary>
        /// <param name="series">引发事件的K线序列</param>
        protected void OpenPosition(KLineSeries series)
        {
            this.AutoTrade(ActionType.OpenPosition, DirectionType.Buy,  this.OpenBuyPosition,  series);
            this.AutoTrade(ActionType.OpenPosition, DirectionType.Sell, this.OpenSellPosition, series);
        }

        /// <summary>
        /// 加仓操作
        /// </summary>
        /// <param name="series">引发事件的K线序列</param>
        protected void IncreasePosition(KLineSeries series)
        {
            this.AutoTrade(ActionType.IncreasePosition, DirectionType.Buy,  this.IncreaseBuyPosition,  series);
            this.AutoTrade(ActionType.IncreasePosition, DirectionType.Sell, this.IncreaseSellPosition, series);
        }

        /// <summary>
        /// 平仓操作
        /// </summary>
        /// <param name="series">引发事件的K线序列</param>
        protected void ClosePosition(KLineSeries series)
        {
            this.AutoTrade(ActionType.ClosePosition, DirectionType.Buy,  this.CloseBuyPosition,  series);
            this.AutoTrade(ActionType.ClosePosition, DirectionType.Sell, this.CloseSellPosition, series);
        }

        /// <summary>
        /// 自动交易
        /// </summary>
        /// <param name="actionType">操作类型（开仓|加仓|平仓）</param>
        /// <param name="directionType">交易方向</param>
        /// <param name="action">操作代理</param>
        /// <param name="series">引发事件的K线序列</param>
        private void AutoTrade(ActionType actionType, DirectionType directionType, DelegateAction action, KLineSeries series)
        {
            //取得当前需要自动交易的K线序列
            this.kLineSeries = series;

            //每个账户逐一判断
            foreach (CtpAccount ctpAccount in this.ctpAccounts)
            {
                //交易委托单
                CtpOrder ctpOrder = new CtpOrder();

                ctpOrder.Policy         = this.PolicyName;
                ctpOrder.Market         = this.kLineSeries.Market;
                ctpOrder.Code           = this.kLineSeries.Code;
                ctpOrder.Level          = this.kLineSeries.Level;
                ctpOrder.Unit           = this.kLineSeries.Unit;
                ctpOrder.Account        = ctpAccount.Account;
                ctpOrder.Direction      = directionType;
                ctpOrder.AccountObject  = ctpAccount;

                Position position = PositionManager.GetInstance().GetPositionById(ctpOrder.GetId());

                //开仓操作
                if (actionType == ActionType.OpenPosition)
                {
                    if (position == null || (position != null && position.Volume <= 0))
                    {
                        if (action())
                        {
                            ctpOrder.Price = this.kLineSeries.Series[0].Close;
                            ctpOrder.Volume = 1;
                            ctpOrder.OpenClose = OpenCloseType.Open;

                            this.tradeManager.Trade(ctpOrder);
                        }
                    }
                }
                //加仓操作
                else if (actionType == ActionType.IncreasePosition)
                {
                    if (position != null && position.Volume > 0)
                    {
                        if (action())
                        {
                            ctpOrder.Price = this.kLineSeries.Series[0].Close;
                            ctpOrder.Volume = 1;
                            ctpOrder.OpenClose = OpenCloseType.Open;

                            this.tradeManager.Trade(ctpOrder);
                        }
                    }
                }
                //平仓操作
                else if (actionType == ActionType.ClosePosition)
                {
                    if (position != null && position.Volume > 0)
                    {
                        if (action())
                        {
                            ctpOrder.Price = this.kLineSeries.Series[0].Close;
                            ctpOrder.Volume = 1;
                            ctpOrder.OpenClose = OpenCloseType.Close;

                            this.tradeManager.Trade(ctpOrder);
                        }
                    }
                }
            }
        }

        /*
        
private delegate bool DelegateOpenPosition(Position position, out double price, out int volume);
private delegate bool DelegateIncreasePosition(Position position, out double price, out int volume);
private delegate bool DelegateClosePosition(Position position, out double price, out int volume);

/// <summary>
/// 开始自动交易
/// </summary>
/// <param name="series">K线序列</param>
protected void StartTrade(KLineSeries series)
{
    this.kLineSeries = series;

    DelegateOpenPosition        openPosition;       //开仓代理
    DelegateIncreasePosition    increasePosition;   //加仓代理
    DelegateClosePosition       closePosition;      //平仓代理

    openPosition        = this.OpenBuyPosition;
    increasePosition    = this.IncreaseBuyPosition;
    closePosition       = this.CloseBuyPosition;

    this.TradeFlow(DirectionType.Buy, openPosition, increasePosition, closePosition);

    openPosition        = this.OpenSellPosition;
    increasePosition    = this.IncreaseSellPosition;
    closePosition       = this.CloseSellPosition;

    this.TradeFlow(DirectionType.Sell, openPosition, increasePosition, closePosition);
}
        
/// <summary>
/// 具体交易流程
/// </summary>
/// <param name="openPosition">开仓代理</param>
/// <param name="increasePosition">加仓代理</param>
/// <param name="closePosition">平仓代理</param>
private void TradeFlow(DirectionType directionType, DelegateOpenPosition openPosition, DelegateIncreasePosition increasePosition, DelegateClosePosition closePosition)
{
    int volume   = 0;
    double price = 0;

    //每个账户逐一判断
    foreach (CtpAccount ctpAccount in this.ctpAccounts)
    {
        //交易委托单
        CtpOrder ctpOrder = new CtpOrder();

        ctpOrder.Policy         = this.PolicyName;
        ctpOrder.Market         = this.kLineSeries.Market;
        ctpOrder.Code           = this.kLineSeries.Code;
        ctpOrder.Level          = this.kLineSeries.Level;
        ctpOrder.Unit           = this.kLineSeries.Unit;
        ctpOrder.Account        = ctpAccount.Account;
        ctpOrder.Direction      = directionType;
        ctpOrder.AccountObject  = ctpAccount;

        Position position = PositionManager.GetInstance().GetPositionById(ctpOrder.GetId());

        //如果有仓位则先判断是否平仓，再判断是否加仓
        if (position != null && position.Volume > 0)
        {
            //平仓判断
            if (closePosition(position, out price, out volume))
            {
                ctpOrder.Price      = price;
                ctpOrder.Volume     = volume;
                ctpOrder.OpenClose  = OpenCloseType.Close;

                //平仓使用相反交易方向以便平仓
                if (ctpOrder.Direction == DirectionType.Buy)
                    ctpOrder.Direction = DirectionType.Sell;
                else
                    ctpOrder.Direction = DirectionType.Buy;

                this.tradeManager.Trade(ctpOrder);

                return;
            }

            //加仓判断
            if (increasePosition(position, out price, out volume))
            {
                ctpOrder.Price      = price;
                ctpOrder.Volume     = volume;
                ctpOrder.OpenClose  = OpenCloseType.Open;

                this.tradeManager.Trade(ctpOrder);

                return;
            }
        }
        //如果没有仓位则进行开新仓判断
        else
        {
            //开新仓判断
            if (openPosition(position, out price, out volume))
            {
                ctpOrder.Price      = price;
                ctpOrder.Volume     = volume;
                ctpOrder.OpenClose  = OpenCloseType.Open;

                this.tradeManager.Trade(ctpOrder);

                return;
            }
        }
    }
}

*/


        /******************************** 策略接口 ********************************/

        /// <summary>
        /// 策略名称
        /// </summary>
        public string PolicyName { get { return this.GetType().Name; } }

        /// <summary>
        /// 策略中文名称
        /// </summary>
        public abstract string PolicyChineseName { get; }

        /// <summary>
        /// K线更新事件处理程序
        /// </summary>
        public abstract void PriceUpdate(KLineSeries series);

        /// <summary>
        /// K线完成事件
        /// </summary>
        public abstract void KLineFinished(KLineSeries series);

        /// <summary>
        /// K线新开事件
        /// </summary>
        public abstract void KLineOpen(KLineSeries series);


        /*************** 多头判断 ***************/

        /// <summary>
        /// 开多仓判断
        /// </summary>
        /// <returns>True为开仓，False为不开仓</returns>
        public abstract bool OpenBuyPosition();

        /// <summary>
        /// 追加多仓判断
        /// </summary>
        /// <returns>True为加仓，False为不加仓</returns>
        public abstract bool IncreaseBuyPosition();

        /// <summary>
        /// 平多仓判断
        /// </summary>
        /// <returns>True为平仓，False为不平仓</returns>
        public abstract bool CloseBuyPosition();


        /*************** 空头判断 ***************/

        /// <summary>
        /// 开空仓判断
        /// </summary>
        /// <returns>True为开仓，False为不开仓</returns>
        public abstract bool OpenSellPosition();

        /// <summary>
        /// 追加空仓判断
        /// </summary>
        /// <returns>True为加仓，False为不加仓</returns>
        public abstract bool IncreaseSellPosition();

        /// <summary>
        /// 平空仓判断
        /// </summary>
        /// <returns>True为平仓，False为不平仓</returns>
        public abstract bool CloseSellPosition();
    }
}
